mod util;
mod demo;
mod router_derive;
mod service_derive;
mod parse;
mod path_derive;

use proc_macro::{ TokenStream };
use proc_macro2::Span;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Expr};
use syn::Expr::Path;
use crate::path_derive::do_rpc_path;
use crate::router_derive::do_receive_router;
use crate::service_derive::{do_rpc_service, do_service};
use crate::util::to_upper_name;

#[proc_macro_attribute]
pub fn rpc_router(attr: TokenStream, item: TokenStream) -> TokenStream {
    do_receive_router(attr, item)
}

#[proc_macro_attribute]
pub fn rpc_service(attr: TokenStream, item: TokenStream) -> TokenStream {
    do_rpc_service(attr, item)
}

#[proc_macro_attribute]
pub fn rpc_path(attr: TokenStream, item: TokenStream) -> TokenStream {
    do_rpc_path(attr, item)
}

#[proc_macro]
pub fn router(input: TokenStream) -> TokenStream {
    let function_name = parse_macro_input!(input as Expr);
    if let Path(mt) = function_name {
        let function_name_to_upper_name = to_upper_name(&mt.path.get_ident().unwrap().to_string());
        let router_factory = syn::Ident::new(&format!("{}RouterFactory", function_name_to_upper_name), Span::call_site());
        let expanded = quote! {
            Box::new(#router_factory)
        };
        return TokenStream::from(expanded);
    }
    panic!("Wrong function name!");
}

#[proc_macro]
pub fn service(input: TokenStream) -> TokenStream {
    do_service(input)
}


#[proc_macro_derive(ImplRpcEncodeDataCast)]
pub fn impl_rpc_encode_data_cast(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = input.ident;
    let expanded = quote! {
        fn cast_to_encode_data(any: &Box<dyn Any>) -> Option<Box<dyn rpc::RpcEncodeData>> {
            let rpc_code = any.downcast_ref::<#name>();
            if let Some(t) = rpc_code {
                let result: Box<dyn rpc::RpcEncodeData> = rpc::RpcEncodeDataFactory::create_data(t);
                Some(result)
            } else {
                None
            }
        }
    };
    expanded.into()
}


